#!/bin/ksh

# defaults
DEFAULT_RC_FILENAME=mxtest.def

#
# Exit with an error message
#
die()
{
  print -u2 "$1"
  exit 1
}

#
# Look for, then source definitions file
#
source_rc_file()
{

  rc_file=${DEFAULT_RC_FILENAME}
  if [[ -n "${MX_TEST_DEF}" ]]; then
    rc_file=${MX_TEST_DEF}
  fi

  for rc_prefix in "" . ${HOME}/ ${HOME}/. ; do
    rc_path=${rc_prefix}${rc_file}
    if [[ -r ${rc_path} ]]; then
      . ${rc_path}
      return 0
    fi
  done

  print -u2 "Cannot open MX test definition file!"
  exit 1
}

#
# Setup variables based on data from RC file
#
setup_variables()
{
  [[ -z "${mx_install}" ]] && die "mx_install must be defined"
  [[ -z "${mx_source}" ]] && die "mx_source must be defined"

  # set up directory locations
  unit_test_dir=${mx_source}/unit_test
  test_list_dir=${unit_test_dir}/tests
  test_obj_dir=${mx_build}/tests

  # build arrays of card types
  num_d_cards=0
  num_any_cards=0
  set - ${d_cards}
  while [[ -n "$*" ]]; do
    d_card[num_d_cards]=$1
    d_card_host[num_d_cards]=${1%:*}
    d_card_index[num_d_cards]=${1#*:}
    let num_d_cards+=1
    any_card[num_any_cards]=$1
    any_card_host[num_any_cards]=${1%:*}
    any_card_index[num_any_cards]=${1#*:}
    let num_any_cards+=1
    shift
  done

  num_e_cards=0
  set - ${e_cards}
  while [[ -n "$*" ]]; do
    e_card[num_e_cards]=$1
    e_card_host[num_e_cards]=${1%:*}
    e_card_index[num_e_cards]=${1#*:}
    let num_e_cards+=1
    any_card[num_any_cards]=$1
    any_card_host[num_any_cards]=${1%:*}
    any_card_index[num_any_cards]=${1#*:}
    let num_any_cards+=1
    shift
  done

  # app directory stuff
  app_bin=${app_dir}/app_bin
  app_log=${app_dir}/app_log
  machfile_dir=${app_dir}/machinefiles
  PATH=${PATH}:${app_bin}:${mx_install}/bin
  export LD_LIBRARY_PATH=${mx_install}/lib

  # Create any directories needed
  mkdir -p ${app_dir} || die "Cannot create directory \"${app_dir}\""
  mkdir -p ${app_bin} || die "Cannot create directory \"${app_bin}\""
  mkdir -p ${app_log} || die "Cannot create directory \"${app_log}\""
  mkdir -p ${machfile_dir} || die "Cannot create directory \"${machfile_dir}\""
}

#
# set the dafaults needed by most tests
#
set_test_defaults()
{
  nic_type=any
  num_processes=1
  test_timeout=10

  pass=0
  skip=0

  pi=0
  while (( pi < 32 )); do
    args[pi]=""
    let pi+=1
  done
  args_cmn=""

  # go to a predictable place
  cd ${app_dir}
}

#
# run_test_single <command>
# run a test on one processor
#
run_test_single()
{
  cmd=${1}
  if [[ -z "${cmd}" ]]; then
    printf "Missing command!\n"
    return 1
  fi

  eval "host=\${${nic_type}_card_host[0]}"
  print "Using host ${host}"
  ssh ${host} PATH=${PATH} LD_LIBRARY_PATH=${LD_LIBRARY_PATH} ${cmd}
  return $?
}

#
# run_test_multi <command>
# run a test on multiple machines
#
run_test_multi()
{
  logfile=${app_log}/${test}

  # build the machine file
  machinefile=${machfile_dir}/${test}
  > ${machinefile}

  # Loop through all hosts
  arglist=""
  pi=0
  while (( pi < num_processes )); do

    # add a host to the hostfile
    eval let hi=pi%num_${nic_type}_cards
    eval print \${${nic_type}_card_host[hi]} >> ${machinefile}

    # XXX should be this: 
    #eval print \${${nic_type}_card_host[hi]} \${${nic_type}_card_index[hi]}

    # create arguments
    if [[ -n "${args[pi]}" ]]; then
      arglist="${arglist} -${pi} \"${args[pi]}\""
    fi

    let pi+=1
  done

  # add common args if any
  if [[ -n "${args_cmn}" ]]; then
    arglist="${arglist} -a \"${args_cmn}\""
  fi

  # Loop through all hosts again, performing name substitution
  pi=0
  while (( pi < num_processes )); do

    eval let hi=pi%num_${nic_type}_cards
    eval arglist=\$\(print -- \${arglist} \| sed s/%%NODE${pi}%%/\${${nic_type}_card[hi]}/g\)

    let pi+=1
  done

  eval mpirun -machinefile ${machinefile} -np ${num_processes} -v $(whence mpi_exec) $(whence $1) ${arglist} \> ${logfile} 2\>\&1

  # indicate pass/fail
  if grep -q FAILED ${logfile}; then
    print "Return failure..."
    return 1
  else
    return 0
  fi
}

#
# run_test <command>
# (needs to be updated to use num_processes and test_timeout)
#
run_test()
{
  if (( num_processes < 2 )); then
    run_test_single $1
  else
    run_test_multi $1
  fi
}

#
# See if mpich has been extracted and built, else do it
#
build_mpich()
{
  # MPI specific vars
  mpich_dirname=mpich-mx
  mpich_dir=${app_dir}/${mpich_dirname}
  mpich_obj=${app_dir}/mpich_mx_obj
  export mpi_src_dir=${unit_test_dir}/src/mpi

  cd ${app_dir} || dir "Cannot cd to ${app_dir}"

  # If the dir exists, don't extract it
  [[ -d ${mpich_dir} ]] && return

  cvs checkout mpich-mx || die "Error extracting MPICH-MX"

  # If no libmpich, build it
  if [[ ! -r ${mpich_obj}/bin/libmpich.a ]]; then
    ( cd mpich-mx && I=${mx_install} MPIHOME=${mpich_obj} ./mpich.make.linux ) ||
      die "Error building MPICH-MX"
  fi

  # add MPICH bin to path
  PATH=$PATH:${mpich_obj}/bin:${app_bin}

  # build MPI utilities
  mkdir -p ${app_bin} || die "Cannot create ${app_bin}"
  cd ${app_bin} || die "Cannot chdir to ${app_bin}"
  make -f ${mpi_src_dir}/Makefile || die "Error making MPI apps"
}

main()
{
  # Grab all the definitions we need for the tests,
  # then use those to setup the variables we need
  source_rc_file
  setup_variables

  # build MPICH if we need it
  build_mpich

  # run all the tests there are
  test_list=$(cd ${test_list_dir}; ls | grep -v CVS)
  fail_list=""
  skip_list=""

  for test in ${test_list}; do
    print "Running ${test}..."
    set_test_defaults
    . ${test_list_dir}/${test}
    if [[ ${pass} = 1 ]]; then
      print "passed"
    elif [[ ${skip} = 1 ]]; then
      print "...skipped..."
      skip_list="${skip_list}${test} "
    else
      print "***FAILED***"
      fail_list="${fail_list}${test} "
    fi
  done

  print ""
  print "========================================="
  print "==              SUMMARY                =="
  print "========================================="
  print ""

  # List those that were skipped
  if [[ -n ${skip_list} ]]; then
    print "Skipped tests:"
    for test in ${skip_list}; do
      print "  ${test}"
    done
  fi
  print ""

  # List those that failed
  if [[ -n ${fail_list} ]]; then
    print "Failing tests:"
    for test in ${fail_list}; do
      print "  ${test}"
    done
  else
    print "No failing tests!"
  fi
}

main $*
